# -*- coding:utf-8 -*-

import os
import sys
import fnmatch
import time
import threading
import thread
import shutil

from MyException import Error, MatchRuleError, GetSizeError, ReadFileError, MoveFileError, DelFileError
from MyLogger import MyLogger, SIZEROTATE, TIMEROTATE
from StatInfo import StatInfo
from StatLog import StatLog

class MatchResult:
    def __init__(self, filename):
        self.filename = filename
        self.ftp_list = []
        self.path_list = []
        
    def match_num(self):
        return len(self.ftp_list) + len(self.path_list)
    
    def show(self):
        print "Match_Result:", self.filename
        print "FTP_List:", len(self.ftp_list)
        print "PATH_List:", len(self.path_list)
        
class Match(threading.Thread):
    def __init__(self, profile, match_rule_list, nomatch_rule_list, statlog_map, send_file_list):
        """
        初始化
        """
        threading.Thread.__init__(self)
        
        self.profile = profile
        
        self.match_rule_list = match_rule_list
        self.nomatch_rule_list = nomatch_rule_list
        
        self.statlog_map = statlog_map
                
        self.send_file_list = send_file_list
        
        self.logger = MyLogger(os.path.join(profile.log_dir, "Match_Result.log"), SIZEROTATE, profile.size_rotate_backup_num)
        
        self.statlog = None

        
    def clear_send_dir(self):
        """
        将发送目录中文件移动到工作目录
        """
        file_list = os.listdir(self.profile.send_dir)
        for filename in file_list:
            srcfile = os.path.join(self.profile.send_dir, filename)
            dstfile = os.path.join(self.profile.work_dir, filename)
            shutil.move(srcfile, dstfile)
            
    def create_statlog(self, file_path):
        """
        创建统计日志信息
        """
        statinfo = StatInfo()
        file_name = os.path.basename(file_path)
        
        #获取文件大小
        try:
            statinfo.file_size = str(os.path.getsize(file_path))
        except os.error, msg:
            raise GetSizeError(msg)
        
        if self.profile.is_write_statlog:   #判断是否需要写统计日志
            #获取文件类型
            index = file_name.rfind(".")
            if index > -1:
                file_type = file_name[index+1:].lower()
            else:
                file_type = "--"
            statinfo.file_type = file_type
            
            #获取地市编号，协议类型，数据源
            if file_type == "xml":
                list = file_name[:-4].split("_")
                if len(list) == 6:
                    statinfo.data_source = list[5]
                    statinfo.protype_desc = list[3]
                    statinfo.uparea_id = list[4]
                    statinfo.file_time = list[1]
            elif file_type == "bcp":
                list = file_name[:-4].split("_")
                if len(list) == 6:
                    statinfo.data_source = list[5]
                    statinfo.protype_desc = list[3]
                    statinfo.uparea_id = list[4]
                    statinfo.file_time = list[1]
                elif len(list) == 8:
                    statinfo.data_source = list[7]
                    statinfo.protype_desc = list[4]
                    statinfo.uparea_id = list[6]
                    statinfo.file_time = list[1]
            elif file_type == "zip":
                list = file_name[:-4].split("_")
                if len(list) == 5:
                    statinfo.uparea_id = list[1]
                    statinfo.data_source = list[2]
                    statinfo.file_time = list[3]
            else:
                pass
            
            #获取数据日期
            statinfo.data_date = time.strftime("%Y%m%d", time.localtime())
            
            #获取记录数
            try:
                if file_type == "bcp":
                    fp = open(file_path)
                    lines = fp.readlines()
                    statinfo.record_num = str(len(lines))
            except Exception, msg:
                raise ReadFileError(msg)
        
        return statinfo
        
    def match_file(self, filename):
        """
        匹配文件名
        """
        #初始化匹配规则
        match_result = MatchResult(filename)
        lower_name = filename.lower()
        
        #匹配所有一般规则
        for match_rule in self.match_rule_list:
            if fnmatch.fnmatch(lower_name, match_rule.rule):
                #print "====>", lower_name, ">~<", match_rule.rule, "<===="
                match_result.ftp_list.extend(match_rule.ftp_list)
                match_result.path_list.extend(match_rule.path_list)
        
        #匹配所有否定规则
        for nomatch_rule in self.nomatch_rule_list:
            if fnmatch.fnmatch(lower_name, nomatch_rule.rule):
                #print "====>", lower_name, ">!<", match_rule.rule, "<===="
                try:
                    for ftp_name in nomatch_rule.ftp_list:
                        match_result.ftp_list.remove(ftp_name)
                    for path_name in nomatch_rule.path_list:
                        match_result.path_list.remove(path_name)
                except ValueError, msg:
                    raise MatchRuleError(msg)
    
        return match_result
        
    def run(self):
        """
        匹配线程执行主体
        """
        #初始化统计日志
        if self.profile.is_write_statlog:
            self.statlog = StatLog(self.profile.statlog_dir, True)
            self.statlog.daemon = True
            self.statlog.start()
        #清理发送目录
        self.clear_send_dir()
        
        while(True):
            try:
                #扫描工作目录，获取文件名
                file_list = os.listdir(self.profile.work_dir)
                
                for filename in file_list:
                    try:
                        try:
                            #拼接文件全路径
                            src_file = os.path.join(self.profile.work_dir, filename)
                            
                            #匹配文件名，获取匹配结果
                            match_result = self.match_file(filename)   
                            
                            #生成统计日志信息
                            statinfo = self.create_statlog(src_file)
                                                 
                            #计算匹配成功数
                            match_num = match_result.match_num()
                            
                            #记录程序日志和统计日志
                            if match_num > 0:  #匹配成功
                                #移动文件
                                try:
                                    dst_file = os.path.join(self.profile.send_dir, filename)
                                    shutil.move(src_file, dst_file)
                                except Exception, msg:
                                    raise MoveFileError(msg)
                                #将统计日志信息和匹配规则加入队列
                                self.statlog_map.insert(filename, statinfo)
                                self.send_file_list.add(match_result)
                                #记录日志
                                if self.profile.is_write_statlog:
                                    self.statlog.write_statlog_amply(filename, statinfo, 0, "match", "")
                                self.logger.info("Success match file: %s size: %s record: %s matches: %d"%(filename, statinfo.file_size, statinfo.record_num, match_num))
                            else:   #匹配失败
                                #删除文件
                                try:
                                    os.remove(src_file)
                                except Exception, msg:
                                    raise DelFileError(msg)
                                #记录日志
                                if self.profile.is_write_statlog:
                                    self.statlog.write_statlog_amply(filename, statinfo, -1, "match", "") 
                                self.logger.error("Error match file: %s size: %s record: %s cause: NoMatched"%(filename, statinfo.file_size, statinfo.record_num))                                
                                    
                        except MatchRuleError, msg:
                            try: 
                                os.remove(src_file)
                            except: 
                                pass
                            self.logger.exception("Error match file: %s size: %s record: %s cause: MatchRule"%(filename, statinfo.file_size, statinfo.record_num))
                            if self.profile.is_write_statlog:
                                self.statlog.write_statlog_amply(filename, statinfo, -1, "match", "")
                        except GetSizeError, msg:
                            self.logger.exception("Error match file: %s size: 0 record: 0 cause: GetSize"%(filename))
                            if self.profile.is_write_statlog:
                                self.statlog.write_statlog_curtly(filename, 0, "--", -1, "match", "")
                        except ReadFileError, msg:
                            try: 
                                os.remove(src_file)
                            except: 
                                pass
                            self.logger.exception("Error match file: %s size: 0 record: 0 cause: ReadFile"%(filename))
                            if self.profile.is_write_statlog:
                                self.statlog.write_statlog_curtly(filename, 0, "--", -1, "match", "")
                        except MoveFileError, msg:
                            self.logger.exception("Error match file: %s size: %s record: %s cause: MoveFile"%(filename, statinfo.file_size, statinfo.record_num))
                            if self.profile.is_write_statlog:
                                self.statlog.write_statlog_amply(filename, statinfo, -1, "match", "")                            
                        except DelFileError, msg:
                            self.logger.exception("Error match file: %s size: %s record: %s cause: DeleteFile"%(filename, statinfo.file_size, statinfo.record_num))
                            if self.profile.is_write_statlog:
                                self.statlog.write_statlog_amply(filename, statinfo, -1, "match", "")
                        except Exception, msg:
                            try:  
                                os.remove(src_file)
                            except: 
                                pass
                            self.logger.exception("Error match file: %s szie: %s record: %s cause: Unknown"%(filename, statinfo.file_size, statinfo.record_num))
                            if self.profile.is_write_statlog:
                                self.statlog.write_statlog_amply(filename, statinfo, -1, "match", "")
                    except:
                        self.logger.exception("unknown error")
            except:
                self.logger.exception("Unknown error")
            
            time.sleep(1)
        
import unittest
import ConfigInfo
import ConfigReader
import ConfigAssist
import MutexMap
import MutexList

class MatchTestCase(unittest.TestCase):
    def setUp(self):
        pass
    
    def tearDown(self):
        pass
            
    def testBaseFunc(self):
        profile = ConfigReader.ConfigReader().read_profile()
        profile.is_write_statlog = True
        all_app_conf, result = ConfigAssist.ConfigAssist().check_match_rule()
        all_app_conf.show()
        
        statinfo_map = MutexMap.MutexMap()
        send_file_list = MutexList.MutexList()
        
        filename = "MASS_1234567890_123456_HTTP_320100_111.bcp"
        fp = open(os.path.join(profile.work_dir, filename), "w")
        fp.write("dsfasadf")
        fp.close()
        
        match = Match(profile, all_app_conf.match_rule_list, all_app_conf.nomatch_rule_list, statinfo_map, send_file_list)
        match.daemon = True
        match.start()
        
        time.sleep(3)
        
        statinfo = statinfo_map.find(filename)
        statinfo.show()
        print send_file_list.copy()[0].show()
        
if __name__ == "__main__":
    suite = unittest.TestSuite()
    suite.addTest(MatchTestCase("testBaseFunc"))  
        
    runner = unittest.TextTestRunner()
    runner.run(suite)

